#!/bin/bash

# ===============================================
# Docker Redis Stack 一键部署脚本
# 文件名 deploy-redis-stack.sh
# 版本: v1.9
# 创建时间: $(date +%Y-%m-%d)
# 功能: 一键部署支持Redis Stack功能的Redis服务
# 更新说明: 
# v1.9 - 添加Redis版本检查功能，支持版本兼容性验证和模块功能检查
# v1.8 - 添加防火墙端口检查功能，支持自动开启所需端口
# v1.7 - 优化镜像源配置，基于日志分析移除无效镜像源，仅保留可正常拉取的镜像源
# v1.6 - 增强Redis Stack功能验证，添加模块检测和功能测试
# v1.5 - 新增Docker镜像加速器自动配置功能，从根本上解决镜像拉取问题
# v1.4 - 优化镜像源配置，增强网络连接检查
# v1.3 - 修复镜像拉取失败问题，优化镜像源配置和错误处理
# v1.2 - 修复镜像源配置错误，优化多镜像源拉取策略
# v1.1 - 增加日志记录功能，优化镜像拉取重试机制
# ===============================================

# 脚本版本信息
SCRIPT_VERSION="v1.9"
SCRIPT_DESCRIPTION="Docker Redis Stack 一键部署脚本"
SCRIPT_UPDATE_INFO="v1.9 - 添加Redis版本检查功能，支持版本兼容性验证和模块功能检查"

# 脚本配置参数
REDIS_CONTAINER_NAME="redis-stack"
REDIS_PASSWORD="Hlj@20220715"
REDIS_PORT="6379"
REDIS_IMAGE="redis/redis-stack-server:latest"

# 版本兼容性配置
MIN_REDIS_VERSION="7.0.0"  # 最低支持的Redis版本
RECOMMENDED_REDIS_VERSION="7.4.6"  # 推荐的Redis版本
REDIS_STACK_MODULES=("search" "json" "timeSeries" "bloom")  # Redis Stack核心模块

# 目录配置
BASE_DIR="/docker/redis-stack"
DATA_DIR="$BASE_DIR/data"
LOG_DIR="$BASE_DIR/logs"
CONF_DIR="$BASE_DIR/conf"

# 日志文件配置（修改为与脚本同级的logs目录）
SCRIPT_BASE_DIR="$(cd "$(dirname "$0")" && pwd)"
SCRIPT_LOG_DIR="$SCRIPT_BASE_DIR/logs"
SCRIPT_LOG_FILE="$SCRIPT_LOG_DIR/deploy-$(date +%Y%m%d-%H%M%S).log"

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# 日志函数
log_info() {
    local message="${BLUE}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
    echo -e "$message"
    echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$SCRIPT_LOG_FILE"
}

log_warn() {
    local message="${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
    echo -e "$message"
    echo "[WARN] $(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$SCRIPT_LOG_FILE"
}

log_error() {
    local message="${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
    echo -e "$message"
    echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$SCRIPT_LOG_FILE"
}

log_success() {
    local message="${GREEN}[SUCCESS]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
    echo -e "$message"
    echo "[SUCCESS] $(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$SCRIPT_LOG_FILE"
}

log_debug() {
    local message="${YELLOW}[DEBUG]${NC} $(date '+%Y-%m-%d %H:%M:%S') - $1"
    echo -e "$message"
    echo "[DEBUG] $(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$SCRIPT_LOG_FILE"
}

# 初始化日志系统
init_log_system() {
    log_info "初始化日志系统..."
    
    # 创建日志目录
    if [ ! -d "$SCRIPT_LOG_DIR" ]; then
        mkdir -p "$SCRIPT_LOG_DIR"
        chmod 755 "$SCRIPT_LOG_DIR"
        log_success "创建日志目录: $SCRIPT_LOG_DIR"
    fi
    
    # 创建日志文件
    touch "$SCRIPT_LOG_FILE"
    chmod 644 "$SCRIPT_LOG_FILE"
    
    # 写入日志头信息
    echo "===============================================" >> "$SCRIPT_LOG_FILE"
    echo "Redis Stack 部署脚本执行日志" >> "$SCRIPT_LOG_FILE"
    echo "脚本版本: v1.8" >> "$SCRIPT_LOG_FILE"
    echo "执行时间: $(date '+%Y-%m-%d %H:%M:%S')" >> "$SCRIPT_LOG_FILE"
    echo "日志文件: $SCRIPT_LOG_FILE" >> "$SCRIPT_LOG_FILE"
    echo "===============================================" >> "$SCRIPT_LOG_FILE"
    echo "" >> "$SCRIPT_LOG_FILE"
    
    log_success "日志系统初始化完成"
    log_info "详细日志将记录到: $SCRIPT_LOG_FILE"
}

# 检查Docker服务状态
check_docker_service() {
    log_info "检查Docker服务状态..."
    
    if ! command -v docker &> /dev/null; then
        log_error "Docker未安装，请先安装Docker"
        return 1
    fi
    
    if ! systemctl is-active --quiet docker; then
        log_error "Docker服务未运行，正在尝试启动..."
        if systemctl start docker; then
            log_success "Docker服务启动成功"
        else
            log_error "Docker服务启动失败"
            return 1
        fi
    fi
    
    log_success "Docker服务状态正常"
    return 0
}

# 检查现有Redis容器
check_existing_redis() {
    log_info "检查现有Redis容器..."
    
    # 检查是否有同名容器
    if docker ps -a --filter "name=$REDIS_CONTAINER_NAME" --format "{{.Names}}" | grep -q .; then
        log_warn "发现现有Redis容器: $REDIS_CONTAINER_NAME"
        
        echo ""
        echo "当前存在的Redis容器信息:"
        docker ps -a --filter "name=$REDIS_CONTAINER_NAME" --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}\t{{.Image}}"
        echo ""
        
        # 询问用户是否删除现有容器
        while true; do
            read -p "是否删除现有Redis容器并重新部署? (yes/no): " choice
            case "$choice" in
                yes|YES|y|Y)
                    log_info "用户选择删除现有容器"
                    
                    # 停止容器
                    if docker ps --filter "name=$REDIS_CONTAINER_NAME" --filter "status=running" --format "{{.Names}}" | grep -q .; then
                        log_info "停止运行中的Redis容器..."
                        docker stop $REDIS_CONTAINER_NAME
                    fi
                    
                    # 删除容器
                    log_info "删除Redis容器..."
                    docker rm $REDIS_CONTAINER_NAME
                    
                    log_success "现有Redis容器已删除"
                    return 0
                    ;;
                no|NO|n|N)
                    log_info "用户选择保留现有容器"
                    log_warn "部署脚本已终止"
                    exit 0
                    ;;
                *)
                    echo "请输入 yes 或 no"
                    ;;
            esac
        done
    else
        log_success "未发现同名Redis容器"
        return 0
    fi
}

# 检查Redis版本信息
check_redis_version() {
    log_info "检查Redis版本信息..."
    
    # 检查容器是否运行
    if ! docker ps --filter "name=$REDIS_CONTAINER_NAME" --filter "status=running" --format "{{.Names}}" | grep -q .; then
        log_warn "Redis容器未运行，跳过版本检查"
        return 0
    fi
    
    # 获取Redis版本信息
    local version_info
    if version_info=$(docker exec $REDIS_CONTAINER_NAME redis-cli -a "$REDIS_PASSWORD" info server 2>/dev/null | grep "redis_version"); then
        local redis_version=$(echo "$version_info" | cut -d: -f2 | tr -d ' ')
        log_success "检测到Redis版本: $redis_version"
        
        # 版本兼容性检查
        if [ "$(echo "$redis_version $MIN_REDIS_VERSION" | tr ' ' '\n' | sort -V | head -n1)" = "$MIN_REDIS_VERSION" ]; then
            log_success "Redis版本 $redis_version 满足最低要求 ($MIN_REDIS_VERSION)"
        else
            log_warn "Redis版本 $redis_version 低于最低要求 ($MIN_REDIS_VERSION)"
        fi
        
        # 检查是否为推荐版本
        if [ "$redis_version" = "$RECOMMENDED_REDIS_VERSION" ]; then
            log_success "当前运行的是推荐的Redis版本: $RECOMMENDED_REDIS_VERSION"
        else
            log_info "当前Redis版本: $redis_version (推荐版本: $RECOMMENDED_REDIS_VERSION)"
        fi
        
        # 记录版本信息到日志
        log_info "Redis详细信息:"
        docker exec $REDIS_CONTAINER_NAME redis-cli -a "$REDIS_PASSWORD" info server 2>/dev/null | grep -E "(redis_version|redis_mode|os|arch_bits|process_id)" | while read line; do
            log_info "  $line"
        done
        
        return 0
    else
        log_error "无法获取Redis版本信息"
        return 1
    fi
}

# 检查Redis Stack模块功能
check_redis_stack_modules() {
    log_info "检查Redis Stack模块功能..."
    
    # 检查容器是否运行
    if ! docker ps --filter "name=$REDIS_CONTAINER_NAME" --filter "status=running" --format "{{.Names}}" | grep -q .; then
        log_warn "Redis容器未运行，跳过模块检查"
        return 0
    fi
    
    local modules_missing=0
    local modules_found=0
    
    log_info "检查Redis Stack核心模块:"
    for module in "${REDIS_STACK_MODULES[@]}"; do
        # 检查模块是否可用
        if docker exec $REDIS_CONTAINER_NAME redis-cli -a "$REDIS_PASSWORD" --eval "return redis.call('command', 'info', '$module')" 0 2>/dev/null | grep -q "unknown"; then
            log_warn "  ❌ $module 模块未找到"
            ((modules_missing++))
        else
            log_success "  ✅ $module 模块可用"
            ((modules_found++))
        fi
    done
    
    # 检查RedisGraph模块（7.2+版本已移除）
    log_info "检查RedisGraph模块（7.2+版本已移除）:"
    if docker exec $REDIS_CONTAINER_NAME redis-cli -a "$REDIS_PASSWORD" --eval "return redis.call('command', 'info', 'graph')" 0 2>/dev/null | grep -q "unknown"; then
        log_info "  ℹ️ graph模块未找到（在Redis Stack 7.2+版本中为可选模块）"
    else
        log_success "  ✅ graph模块可用"
        ((modules_found++))
    fi
    
    # 总结模块检查结果
    if [ $modules_found -gt 0 ]; then
        log_success "Redis Stack模块检查完成: $modules_found 个模块可用"
        if [ $modules_missing -gt 0 ]; then
            log_warn "有 $modules_missing 个模块未找到，但核心功能正常"
        fi
    else
        log_error "未找到任何Redis Stack模块，请检查Redis Stack安装"
        return 1
    fi
    
    return 0
}

# 检查防火墙端口状态
check_firewall_ports() {
    log_info "检查防火墙端口状态..."
    
    local redis_port=$REDIS_PORT
    local management_port=8001
    local firewall_tool=""
    local ports_to_check=("$redis_port" "$management_port")
    
    # 检测防火墙工具
    if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active firewalld >/dev/null 2>&1; then
        firewall_tool="firewalld"
        log_info "检测到防火墙系统: firewalld"
    elif command -v ufw >/dev/null 2>&1; then
        firewall_tool="ufw"
        log_info "检测到防火墙系统: ufw"
    elif command -v iptables >/dev/null 2>&1; then
        firewall_tool="iptables"
        log_info "检测到防火墙系统: iptables"
    else
        log_warn "未检测到常见的防火墙工具，跳过端口检查"
        return 0
    fi
    
    # 检查端口状态
    local all_ports_open=true
    
    for port in "${ports_to_check[@]}"; do
        local port_open=false
        
        case "$firewall_tool" in
            "firewalld")
                if firewall-cmd --query-port="$port/tcp" >/dev/null 2>&1; then
                    port_open=true
                fi
                ;;
            "ufw")
                if ufw status | grep -q "$port/tcp.*ALLOW"; then
                    port_open=true
                fi
                ;;
            "iptables")
                if iptables -L INPUT -n | grep -q ":$port.*ACCEPT"; then
                    port_open=true
                fi
                ;;
        esac
        
        if [ "$port_open" = "true" ]; then
            log_success "端口 $port/tcp 已开放"
        else
            log_warn "端口 $port/tcp 未开放"
            all_ports_open=false
        fi
    done
    
    if [ "$all_ports_open" = "true" ]; then
        log_success "所有必需端口均已开放"
        return 0
    else
        log_warn "部分端口未开放，需要配置防火墙"
        return 1
    fi
}

# 自动开启防火墙端口
auto_open_firewall_ports() {
    log_info "自动开启防火墙端口..."
    
    local redis_port=$REDIS_PORT
    local management_port=8001
    local firewall_tool=""
    
    # 重新检测防火墙工具
    if command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active firewalld >/dev/null 2>&1; then
        firewall_tool="firewalld"
    elif command -v ufw >/dev/null 2>&1; then
        firewall_tool="ufw"
    elif command -v iptables >/dev/null 2>&1; then
        firewall_tool="iptables"
    else
        log_error "无法确定防火墙工具，无法自动开启端口"
        return 1
    fi
    
    # 开启端口
    case "$firewall_tool" in
        "firewalld")
            log_info "使用firewalld开启端口..."
            
            # 开启Redis端口
            if ! firewall-cmd --query-port="$redis_port/tcp" >/dev/null 2>&1; then
                firewall-cmd --permanent --add-port="$redis_port/tcp"
                if [ $? -eq 0 ]; then
                    log_success "已添加Redis端口 $redis_port/tcp"
                else
                    log_error "添加Redis端口失败"
                    return 1
                fi
            fi
            
            # 开启管理界面端口
            if ! firewall-cmd --query-port="$management_port/tcp" >/dev/null 2>&1; then
                firewall-cmd --permanent --add-port="$management_port/tcp"
                if [ $? -eq 0 ]; then
                    log_success "已添加管理界面端口 $management_port/tcp"
                else
                    log_error "添加管理界面端口失败"
                    return 1
                fi
            fi
            
            # 重新加载防火墙配置
            firewall-cmd --reload
            if [ $? -eq 0 ]; then
                log_success "防火墙配置已重新加载"
            else
                log_error "防火墙重新加载失败"
                return 1
            fi
            ;;
            
        "ufw")
            log_info "使用ufw开启端口..."
            
            # 检查ufw状态，如果未启用则启用
            if ufw status | grep -q "Status: inactive"; then
                log_info "ufw未启用，正在启用..."
                echo "y" | ufw enable
            fi
            
            # 开启Redis端口
            if ! ufw status | grep -q "$redis_port/tcp.*ALLOW"; then
                ufw allow "$redis_port/tcp"
                if [ $? -eq 0 ]; then
                    log_success "已允许Redis端口 $redis_port/tcp"
                else
                    log_error "允许Redis端口失败"
                    return 1
                fi
            fi
            
            # 开启管理界面端口
            if ! ufw status | grep -q "$management_port/tcp.*ALLOW"; then
                ufw allow "$management_port/tcp"
                if [ $? -eq 0 ]; then
                    log_success "已允许管理界面端口 $management_port/tcp"
                else
                    log_error "允许管理界面端口失败"
                    return 1
                fi
            fi
            ;;
            
        "iptables")
            log_info "使用iptables开启端口..."
            
            # 开启Redis端口
            if ! iptables -L INPUT -n | grep -q ":$redis_port.*ACCEPT"; then
                iptables -A INPUT -p tcp --dport "$redis_port" -j ACCEPT
                if [ $? -eq 0 ]; then
                    log_success "已添加Redis端口 $redis_port/tcp 规则"
                else
                    log_error "添加Redis端口规则失败"
                    return 1
                fi
            fi
            
            # 开启管理界面端口
            if ! iptables -L INPUT -n | grep -q ":$management_port.*ACCEPT"; then
                iptables -A INPUT -p tcp --dport "$management_port" -j ACCEPT
                if [ $? -eq 0 ]; then
                    log_success "已添加管理界面端口 $management_port/tcp 规则"
                else
                    log_error "添加管理界面端口规则失败"
                    return 1
                fi
            fi
            
            # 保存iptables规则（如果支持）
            if command -v iptables-save >/dev/null 2>&1; then
                iptables-save > /etc/iptables/rules.v4
                log_success "iptables规则已保存"
            fi
            ;;
    esac
    
    log_success "防火墙端口配置完成"
    return 0
}

# 创建目录结构
create_directories() {
    log_info "创建目录结构..."
    
    # 创建基础目录
    for dir in "$BASE_DIR" "$DATA_DIR" "$LOG_DIR" "$CONF_DIR"; do
        if [ ! -d "$dir" ]; then
            mkdir -p "$dir"
            log_success "创建目录: $dir"
        else
            log_warn "目录已存在: $dir"
        fi
    done
    
    # 设置目录权限
    chmod 755 "$BASE_DIR"
    chmod 700 "$DATA_DIR"
    chmod 755 "$LOG_DIR"
    chmod 755 "$CONF_DIR"
    
    log_success "目录结构创建完成"
}

# 创建Redis配置文件
create_redis_config() {
    log_info "创建Redis配置文件..."
    
    local config_file="$CONF_DIR/redis.conf"
    
    cat > "$config_file" << EOF
# Redis Stack 配置文件
# 生成时间: $(date)

# 基础配置
bind 0.0.0.0
port $REDIS_PORT
requirepass $REDIS_PASSWORD

# 数据持久化
save 900 1
save 300 10
save 60 10000
stop-writes-on-bgsave-error yes
rdbcompression yes
rdbchecksum yes
dbfilename dump.rdb
dir /data

# 内存管理
maxmemory 1gb
maxmemory-policy allkeys-lru

# 日志配置
loglevel notice
logfile /logs/redis.log

# 安全配置
protected-mode no

# 网络配置
tcp-keepalive 300
timeout 0

# 高级配置
hash-max-ziplist-entries 512
hash-max-ziplist-value 64
list-max-ziplist-size -2
list-compress-depth 0
set-max-intset-entries 512
zset-max-ziplist-entries 128
zset-max-ziplist-value 64

# Redis Stack 特定配置
# 启用RedisJSON模块
loadmodule /opt/redis-stack/lib/redisjson.so
# 启用RediSearch模块
loadmodule /opt/redis-stack/lib/redisearch.so
# 启用RedisGraph模块
loadmodule /opt/redis-stack/lib/redisgraph.so
# 启用RedisTimeSeries模块
loadmodule /opt/redis-stack/lib/redistimeseries.so
# 启用RedisBloom模块
loadmodule /opt/redis-stack/lib/redisbloom.so
EOF
    
    if [ -f "$config_file" ]; then
        log_success "Redis配置文件创建成功: $config_file"
        return 0
    else
        log_error "Redis配置文件创建失败"
        return 1
    fi
}

# 配置Docker镜像加速器
configure_docker_mirrors() {
    log_info "配置Docker镜像加速器..."
    
    # 检查是否已配置镜像加速器
    if [ -f "/etc/docker/daemon.json" ]; then
        log_info "检测到已存在的Docker配置文件"
        if grep -q "registry-mirrors" "/etc/docker/daemon.json"; then
            log_success "Docker镜像加速器已配置"
            return 0
        fi
    fi
    
    # 创建Docker配置目录
    sudo mkdir -p /etc/docker
    
    # 配置镜像加速器（使用用户提供的镜像源）
    log_info "配置镜像加速器..."
    sudo tee /etc/docker/daemon.json <<-'EOF'
{
    "registry-mirrors": [
        "https://docker.unsee.tech",
        "https://dockerpull.org",
        "https://docker.1panel.live",
        "https://dockerhub.icu"
    ]
}
EOF
    
    if [ $? -eq 0 ]; then
        log_success "Docker镜像加速器配置成功"
        
        # 重启Docker服务
        log_info "重启Docker服务以应用配置..."
        sudo systemctl daemon-reload
        sudo systemctl restart docker
        
        # 等待Docker服务启动
        sleep 5
        
        if sudo systemctl is-active --quiet docker; then
            log_success "Docker服务重启成功"
            return 0
        else
            log_warn "Docker服务重启失败，但配置已保存"
            return 1
        fi
    else
        log_error "Docker镜像加速器配置失败"
        return 1
    fi
}

# 检查网络连接
check_network_connection() {
    log_info "检查网络连接状态..."
    
    # 检查基础网络连接
    log_info "检查基础网络连接..."
    if ping -c 3 -W 5 8.8.8.8 > /dev/null 2>&1; then
        log_success "基础网络连接正常"
    else
        log_warn "基础网络连接异常"
        return 1
    fi
    
    # 检查Docker Hub连接
    log_info "检查Docker Hub连接..."
    if curl -s --connect-timeout 30 https://registry-1.docker.io/v2/ > /dev/null; then
        log_success "Docker Hub连接正常"
        return 0
    else
        log_warn "Docker Hub连接异常，将配置镜像加速器"
        
        # 配置Docker镜像加速器
        if configure_docker_mirrors; then
            log_success "镜像加速器配置完成，重新检查连接..."
            # 重新检查连接
            if curl -s --connect-timeout 30 https://registry-1.docker.io/v2/ > /dev/null; then
                log_success "镜像加速器生效，Docker Hub连接正常"
                return 0
            else
                log_warn "镜像加速器可能未生效，使用备用镜像源"
                REDIS_IMAGE="registry.cn-hangzhou.aliyuncs.com/library/redis-stack-server:latest"
                return 0
            fi
        else
            log_warn "镜像加速器配置失败，使用备用镜像源"
            REDIS_IMAGE="registry.cn-hangzhou.aliyuncs.com/library/redis-stack-server:latest"
            return 0
        fi
    fi
}

# 拉取Redis Stack镜像
pull_redis_image() {
    log_info "开始拉取Redis Stack镜像"
    
    # 定义镜像源（基于日志分析，仅保留可正常拉取的镜像源）
    local image_sources=(
        "docker.1panel.live/redis/redis-stack-server:latest"  # 1panel镜像源（已验证可用）
    )
    
    local max_retries=3
    local timeout=600  # 10分钟超时
    
    # 首先检查网络连接
    log_info "检查网络连接状态..."
    if ! ping -c 3 -W 5 8.8.8.8 > /dev/null 2>&1; then
        log_warn "基础网络连接异常，尝试使用本地镜像源"
        # 如果网络不通，尝试使用本地镜像
        if docker images | grep -q "redis-stack-server"; then
            log_success "发现本地Redis Stack镜像"
            REDIS_IMAGE="redis/redis-stack-server:latest"
            return 0
        fi
    fi
    
    for source in "${image_sources[@]}"; do
        log_info "尝试镜像源: $source"
        
        local retry_count=0
        while [ $retry_count -lt $max_retries ]; do
            retry_count=$((retry_count + 1))
            log_info "第${retry_count}次尝试拉取镜像..."
            
            # 执行镜像拉取，捕获详细错误信息
            local pull_output
            pull_output=$(timeout $timeout docker pull "$source" 2>&1)
            local pull_exit_code=$?
            
            echo "镜像拉取输出: $pull_output" >> "$SCRIPT_LOG_FILE"
            
            if [ $pull_exit_code -eq 0 ]; then
                log_success "镜像拉取成功!"
                log_info "镜像详细信息:"
                docker image inspect "$source" --format="Size: {{.Size}} bytes, Created: {{.Created}}, Architecture: {{.Architecture}}" >> "$SCRIPT_LOG_FILE"
                
                # 如果使用的是镜像源，重新标记为官方镜像名
                if [[ "$source" != "docker.io/redis/redis-stack-server:latest" ]]; then
                    log_info "重新标记镜像为官方名称..."
                    docker tag "$source" "redis/redis-stack-server:latest"
                    REDIS_IMAGE="redis/redis-stack-server:latest"
                else
                    REDIS_IMAGE="$source"
                fi
                
                return 0
            else
                log_warn "镜像拉取失败 (尝试 ${retry_count}/${max_retries})"
                log_info "错误详情: $pull_output"
                
                # 分析错误类型
                if echo "$pull_output" | grep -q "access denied"; then
                    log_info "镜像源需要认证，跳过此源"
                    break
                elif echo "$pull_output" | grep -q "not found"; then
                    log_info "镜像不存在，跳过此源"
                    break
                elif echo "$pull_output" | grep -q "timeout"; then
                    log_info "网络超时，等待后重试"
                fi
                
                # 等待时间递增
                local wait_time=$((retry_count * 10))
                log_info "等待${wait_time}秒后重试..."
                sleep $wait_time
            fi
        done
        
        log_warn "镜像源 $source 拉取失败，尝试下一个镜像源"
    done
    
    # 如果所有镜像源都失败，尝试使用备用方案
    log_info "所有镜像源拉取失败，尝试备用方案..."
    
    # 方案1: 检查是否有本地镜像
    if docker images | grep -q "redis-stack-server"; then
        log_success "使用本地已有的Redis Stack镜像"
        REDIS_IMAGE="redis/redis-stack-server:latest"
        return 0
    fi
    
    # 方案2: 尝试使用Redis官方镜像（基础版）
    log_info "尝试使用Redis官方镜像作为替代方案..."
    if docker pull redis:7.2-alpine; then
        log_success "成功拉取Redis官方镜像"
        REDIS_IMAGE="redis:7.2-alpine"
        log_warn "注意：使用Redis官方镜像，Redis Stack功能将不可用"
        return 0
    fi
    
    log_error "所有镜像拉取方案均失败"
    log_info "故障排除建议:"
    log_info "1. 检查网络连接: ping 8.8.8.8"
    log_info "2. 配置Docker镜像加速器（推荐方案）:"
    log_info "   sudo mkdir -p /etc/docker"
    log_info "   sudo tee /etc/docker/daemon.json <<-'EOF'"
    log_info "   {""
    log_info "     \"registry-mirrors\": [""
    log_info "       \"https://docker.mirrors.ustc.edu.cn\",""
    log_info "       \"https://hub-mirror.c.163.com\",""
    log_info "       \"https://registry.docker-cn.com\"""
    log_info "     ]""
    log_info "   }""
    log_info "   EOF""
    log_info "   sudo systemctl daemon-reload""
    log_info "   sudo systemctl restart docker""
    log_info "3. 手动拉取镜像: docker pull redis/redis-stack-server:latest"
    log_info "4. 检查防火墙设置"
    return 1
}

# 启动Redis Stack容器
start_redis_container() {
    log_info "启动Redis Stack容器..."
    
    # 检查容器是否已存在
    if docker ps -a --filter "name=$REDIS_CONTAINER_NAME" --format "{{.Names}}" | grep -q .; then
        log_error "Redis容器已存在，无法启动"
        return 1
    fi
    
    # 启动容器
    local docker_cmd="docker run -d \\
        --name $REDIS_CONTAINER_NAME \\
        --restart unless-stopped \\
        -p $REDIS_PORT:$REDIS_PORT \\
        -p 8001:8001 \\
        -v $DATA_DIR:/data \\
        -v $LOG_DIR:/logs \\
        -v $CONF_DIR:/conf \\
        -e REDIS_ARGS=\"--requirepass $REDIS_PASSWORD --port $REDIS_PORT\" \\
        $REDIS_IMAGE"
    
    log_info "执行启动命令: $docker_cmd"
    
    if eval "$docker_cmd"; then
        # 等待容器启动
        sleep 5
        
        # 验证容器状态
        if docker ps --filter "name=$REDIS_CONTAINER_NAME" --filter "status=running" --format "{{.Names}}" | grep -q .; then
            log_success "Redis Stack容器启动成功"
            return 0
        else
            log_error "Redis Stack容器启动后异常停止"
            docker logs $REDIS_CONTAINER_NAME --tail 10
            return 1
        fi
    else
        log_error "Redis Stack容器启动失败"
        return 1
    fi
}

# 验证Redis Stack服务
verify_redis_service() {
    log_info "验证Redis Stack服务状态..."
    
    # 等待Redis服务启动
    log_info "等待Redis服务启动..."
    local max_wait=30
    local wait_count=0
    
    while [ $wait_count -lt $max_wait ]; do
        if docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" ping 2>/dev/null | grep -q "PONG"; then
            log_success "Redis服务启动成功"
            break
        fi
        
        wait_count=$((wait_count + 1))
        sleep 1
    done
    
    if [ $wait_count -ge $max_wait ]; then
        log_error "Redis服务启动超时"
        return 1
    fi
    
    # 测试基本功能
    log_info "测试Redis基本功能..."
    if docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" set test_key "test_value" > /dev/null 2>&1 && \
       docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" get test_key 2>/dev/null | grep -q "test_value"; then
        log_success "Redis基本功能测试通过"
        
        # 清理测试数据
        docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" del test_key > /dev/null 2>&1
    else
        log_error "Redis基本功能测试失败"
        return 1
    fi
    
    # 验证Redis Stack模块
    log_info "验证Redis Stack模块支持..."
    
    # 检查已加载的模块
    local module_info
    module_info=$(docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" module list 2>/dev/null)
    
    if [ $? -eq 0 ]; then
        log_success "Redis模块系统正常"
        echo "已加载模块信息:" >> "$SCRIPT_LOG_FILE"
        echo "$module_info" >> "$SCRIPT_LOG_FILE"
        
        # 检查关键模块
        local required_modules=("ReJSON" "search" "graph" "timeseries" "bf")
        local missing_modules=()
        
        for module in "${required_modules[@]}"; do
            if echo "$module_info" | grep -qi "$module"; then
                log_success "✅ $module 模块已加载"
            else
                log_warn "⚠️ $module 模块未找到"
                missing_modules+=("$module")
            fi
        done
        
        if [ ${#missing_modules[@]} -eq 0 ]; then
            log_success "所有Redis Stack模块加载成功"
        else
            log_warn "部分Redis Stack模块缺失: ${missing_modules[*]}"
        fi
        
        # 测试RedisJSON功能
        log_info "测试RedisJSON功能..."
        local json_test_result
        json_test_result=$(docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" --eval /dev/stdin <<-'EOF' 2>&1
JSON.SET test_json . '{"name":"test","value":123}'
JSON.GET test_json
EOF
        )
        
        if [ $? -eq 0 ] && echo "$json_test_result" | grep -q '"name":"test"'; then
            log_success "RedisJSON功能测试通过"
            # 清理测试数据
            docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" del test_json > /dev/null 2>&1
        else
            log_warn "RedisJSON功能测试失败，可能模块未完全加载"
            log_debug "测试输出: $json_test_result"
        fi
        
        # 测试RediSearch功能
        log_info "测试RediSearch功能..."
        local search_test_result
        search_test_result=$(docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" --eval /dev/stdin <<-'EOF' 2>&1
FT.CREATE test_idx ON HASH PREFIX 1 test: SCHEMA name TEXT
HSET test:1 name "test document"
FT.SEARCH test_idx "test"
EOF
        )
        
        if [ $? -eq 0 ] && echo "$search_test_result" | grep -q "test document"; then
            log_success "RediSearch功能测试通过"
            # 清理测试数据
            docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" del test:1 > /dev/null 2>&1
            docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" FT.DROP test_idx > /dev/null 2>&1
        else
            log_warn "RediSearch功能测试失败，可能模块未完全加载"
            log_debug "测试输出: $search_test_result"
        fi
        
        # 测试RedisGraph功能
        log_info "测试RedisGraph功能..."
        local graph_test_result
        graph_test_result=$(docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" --eval /dev/stdin <<-'EOF' 2>&1
GRAPH.QUERY test_graph "CREATE (:Person {name: 'Alice', age: 30})"
GRAPH.QUERY test_graph "MATCH (p:Person) RETURN p.name, p.age"
EOF
        )
        
        if [ $? -eq 0 ] && echo "$graph_test_result" | grep -q "Alice"; then
            log_success "RedisGraph功能测试通过"
            # 清理测试数据
            docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" GRAPH.DELETE test_graph > /dev/null 2>&1
        else
            log_warn "RedisGraph功能测试失败，可能模块未完全加载"
            log_debug "测试输出: $graph_test_result"
        fi
        
        # 测试RedisTimeSeries功能
        log_info "测试RedisTimeSeries功能..."
        local timeseries_test_result
        timeseries_test_result=$(docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" --eval /dev/stdin <<-'EOF' 2>&1
TS.CREATE test_ts
TS.ADD test_ts 1000 25
TS.GET test_ts
EOF
        )
        
        if [ $? -eq 0 ] && echo "$timeseries_test_result" | grep -q "25"; then
            log_success "RedisTimeSeries功能测试通过"
            # 清理测试数据
            docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" TS.DEL test_ts > /dev/null 2>&1
        else
            log_warn "RedisTimeSeries功能测试失败，可能模块未完全加载"
            log_debug "测试输出: $timeseries_test_result"
        fi
        
        # 测试RedisBloom功能
        log_info "测试RedisBloom功能..."
        local bloom_test_result
        bloom_test_result=$(docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" --eval /dev/stdin <<-'EOF' 2>&1
BF.ADD test_bloom "item1"
BF.EXISTS test_bloom "item1"
EOF
        )
        
        if [ $? -eq 0 ] && echo "$bloom_test_result" | grep -q "1"; then
            log_success "RedisBloom功能测试通过"
            # 清理测试数据
            docker exec "$REDIS_CONTAINER_NAME" redis-cli -a "$REDIS_PASSWORD" DEL test_bloom > /dev/null 2>&1
        else
            log_warn "RedisBloom功能测试失败，可能模块未完全加载"
            log_debug "测试输出: $bloom_test_result"
        fi
        
    else
        log_error "无法获取模块信息，Redis Stack可能未正确安装"
        return 1
    fi
    
    # 检查Redis Stack管理界面
    log_info "检查Redis Stack管理界面..."
    local management_accessible=false
    
    # 检查本地访问
    if curl -s http://localhost:8001 > /dev/null 2>&1; then
        log_success "Redis Stack管理界面本地可访问 (http://localhost:8001)"
        management_accessible=true
    else
        log_warn "Redis Stack管理界面本地无法访问"
    fi
    
    # 检查外网访问（获取服务器IP）
    local server_ip
    server_ip=$(curl -s ifconfig.me 2>/dev/null || echo "unknown")
    
    if [ "$server_ip" != "unknown" ]; then
        if curl -s --connect-timeout 5 http://$server_ip:8001 > /dev/null 2>&1; then
            log_success "Redis Stack管理界面外网可访问 (http://$server_ip:8001)"
            management_accessible=true
        else
            log_warn "Redis Stack管理界面外网无法访问 (http://$server_ip:8001)"
            log_info "请检查防火墙设置，确保8001端口已开放"
        fi
    else
        log_warn "无法获取服务器外网IP，跳过外网访问检查"
    fi
    
    if [ "$management_accessible" = "false" ]; then
        log_warn "Redis Stack管理界面无法访问，请检查容器日志和防火墙设置"
    fi
    
    # 输出完整的验证报告
    log_info "=== Redis Stack验证报告 ==="
    log_info "✅ Redis基础服务: 正常"
    log_info "✅ Redis模块系统: 正常"
    log_info "📊 已加载模块: $(echo "$module_info" | wc -l) 个"
    log_info "🌐 管理界面: http://localhost:8001"
    log_info "🔑 连接信息: redis-cli -h localhost -p 6379 -a Hlj@20220715"
    
    return 0
}

# 显示部署信息
show_deployment_info() {
    echo ""
    echo "==============================================="
    echo "        Redis Stack 部署完成"
    echo "==============================================="
    echo ""
    echo "部署信息:"
    echo "  容器名称: $REDIS_CONTAINER_NAME"
    echo "  Redis端口: $REDIS_PORT"
    echo "  连接密码: $REDIS_PASSWORD"
    echo ""
    echo "目录结构:"
    echo "  基础目录: $BASE_DIR"
    echo "  数据目录: $DATA_DIR"
    echo "  日志目录: $LOG_DIR"
    echo "  配置目录: $CONF_DIR"
    echo ""
    echo "连接信息:"
    echo "  本地连接: redis-cli -h 127.0.0.1 -p $REDIS_PORT -a $REDIS_PASSWORD"
    echo "  远程连接: redis-cli -h <服务器IP> -p $REDIS_PORT -a $REDIS_PASSWORD"
    echo ""
    echo "管理界面:"
    echo "  本地访问: http://localhost:8001"
    echo "  外网访问: http://<服务器IP>:8001"
    echo ""
    echo "运维命令:"
    echo "  查看状态: docker ps --filter name=$REDIS_CONTAINER_NAME"
    echo "  查看日志: docker logs $REDIS_CONTAINER_NAME"
    echo "  停止服务: docker stop $REDIS_CONTAINER_NAME"
    echo "  启动服务: docker start $REDIS_CONTAINER_NAME"
    echo ""
    echo "Redis Stack功能:"
    echo "  ✅ RedisJSON - JSON数据支持"
    echo "  ✅ RediSearch - 全文搜索"
    echo "  ✅ RedisGraph - 图数据库"
    echo "  ✅ RedisTimeSeries - 时间序列数据"
    echo "  ✅ RedisBloom - 概率数据结构"
    echo ""
    echo "防火墙配置:"
    echo "  确保以下端口已开放:"
    echo "  - Redis端口: $REDIS_PORT (TCP)"
    echo "  - 管理界面: 8001 (TCP)"
    echo ""
    echo "故障排除:"
    echo "  1. 检查防火墙设置"
    echo "  2. 查看容器日志: docker logs $REDIS_CONTAINER_NAME"
    echo "  3. 检查端口映射: docker port $REDIS_CONTAINER_NAME"
    echo ""
    echo "注意: 如果外网无法访问管理界面，请检查服务器防火墙和云服务商安全组设置"
}

# 主部署函数
main_deployment() {
    # 初始化日志系统
    init_log_system
    
    log_info "开始Redis Stack部署流程..."
    
    # 检查Docker服务
    if ! check_docker_service; then
        return 1
    fi
    
    # 检查现有Redis容器
    if ! check_existing_redis; then
        return 1
    fi
    
    # 检查防火墙端口状态
    if ! check_firewall_ports; then
        log_warn "检测到防火墙端口未完全开放"
        log_info "是否自动开启所需端口？(y/N)"
        read -r response
        if [[ "$response" =~ ^[Yy]$ ]]; then
            if ! auto_open_firewall_ports; then
                log_error "自动开启防火墙端口失败"
                log_info "请手动配置防火墙或继续部署（可能影响外部访问）"
                log_info "是否继续部署？(y/N)"
                read -r continue_response
                if [[ ! "$continue_response" =~ ^[Yy]$ ]]; then
                    return 1
                fi
            fi
        else
            log_warn "跳过防火墙端口自动开启"
            log_info "请确保以下端口已手动开放：$REDIS_PORT/tcp 和 8001/tcp"
        fi
    fi
    
    # 创建目录结构
    if ! create_directories; then
        return 1
    fi
    
    # 创建配置文件
    if ! create_redis_config; then
        return 1
    fi
    
    # 拉取镜像
    if ! pull_redis_image; then
        return 1
    fi
    
    # 启动容器
    if ! start_redis_container; then
        return 1
    fi
    
    # 验证服务
    if ! verify_redis_service; then
        return 1
    fi
    
    # 检查Redis版本信息
    if ! check_redis_version; then
        log_warn "Redis版本检查失败，但服务已正常运行"
    fi
    
    # 检查Redis Stack模块功能
    if ! check_redis_stack_modules; then
        log_warn "Redis Stack模块检查失败，但服务已正常运行"
    fi
    
    # 显示部署信息
    show_deployment_info
    
    log_success "Redis Stack部署完成"
    return 0
}

# 脚本执行入口
if [ "$1" = "--version" ] || [ "$1" = "-v" ]; then
    echo "Docker Redis Stack 一键部署脚本 v1.8"
    exit 0
fi

if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
    echo ""
    echo "使用说明: ./deploy-redis-stack.sh"
    echo ""
    echo "选项:"
    echo "  -v, --version    显示版本信息"
    echo "  -h, --help       显示帮助信息"
    echo ""
    exit 0
fi

# 执行主部署流程
main_deployment

# 返回退出代码
exit_code=$?
if [ $exit_code -eq 0 ]; then
    log_success "部署脚本执行完成"
else
    log_error "部署脚本执行失败"
fi

exit $exit_code